package com.andox.fn.inf.rpc.rest.common;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.andox.fn.inf.rpc.rest.util.ClassHelper;
import com.andox.fn.inf.rpc.rest.util.ClassUtils;

/**
 * @ClassName: AbstractCompiler
 * @Description: TODO
 * @author: Andox
 * @date: 2019年7月29日 下午2:06:22
 * 
 */
public abstract class AbstractCompiler {
	private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");

	private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");

	public Class<?> compile(String code, ClassLoader classLoader) {
		code = code.trim();
		Matcher matcher = PACKAGE_PATTERN.matcher(code);
		String pkg;
		if (matcher.find()) {
			pkg = matcher.group(1);
		} else {
			pkg = "";
		}
		matcher = CLASS_PATTERN.matcher(code);
		String cls;
		if (matcher.find()) {
			cls = matcher.group(1);
		} else {
			throw new IllegalArgumentException("No such class name in " + code);
		}
		String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
		try {
			return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
		} catch (ClassNotFoundException e) {
			if (!code.endsWith("}")) {
				throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
			}
			try {
				System.err.println(code);
				return doCompile(className, code);
			} catch (RuntimeException t) {
				throw t;
			} catch (Throwable t) {
				throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: "
						+ className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
			}
		}
	}

	protected abstract Class<?> doCompile(String name, String source) throws Throwable;
}
